﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Printing;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Xps;
using System.Windows.Xps.Packaging;
using RG.Common.Const;
using RG.Common.WPF.Commands;
using RG.Common.WPF.Frames;
using RG.Common.WPF.Reporting;
using RG.Common.WPF.Reporting.XPS_Utils;
using RG.Common.WPF.Workplaces;
using Microsoft.Practices.Unity;
using RG.Common;
using RG.Common.WPF;

namespace RG.Common.WPF
{
    [SupportDataBinding]
    public class ReportPrintFrameVM : IFrameForMultiWorkplace, IReportFrameVM
    {
        [Dependency]
        public IUnityContainer Cfg { get; set; }

        [Dependency]
        public WorkplaceWorker Worker { get; set; }

        public FixedDocumentSequence ReportDoc { get; set; }
        List<PageItem> sourcePages;

        public bool IsMailButton { get { return true; } }
        public ICommand SendMailCmd { get; set; }
        public ICommand PrintCmd { get; set; }
        private readonly List<string> PackUriNames = new List<string>();

        public object RepFactory { get; set; }

        public ReportPrintFrameVM()
        {
            SendMailCmd = new DelegateCommand(
                () => ReportDoc.ToMAPI(Name, Name),
                () => Worker.IsFree && ReportDoc != null);
            PrintCmd = new DelegateCommand(DoPrint, () => Worker.IsFree && ReportDoc != null);
        }

        private void DoPrint()
        {
            var prDlg = new PrintDialog();
            sourcePages = new List<PageItem>();

            if (ReportDoc != null)
            {
                if (RepFactory is IValidateBeforePrint && !((IValidateBeforePrint)RepFactory).DoValidate()) return;
                var doc = ReportDoc.References[0].GetDocument(true);
                if (doc != null)
                    foreach (var pageContent in doc.Pages)
                        sourcePages.Add(new PageItem(pageContent));

                prDlg.MinPage = 1;
                prDlg.MaxPage = (uint)sourcePages.Count;
                prDlg.UserPageRangeEnabled = true;
                if (ReportDoc.DocumentPaginator.PageSize.Width > ReportDoc.DocumentPaginator.PageSize.Height)
                    prDlg.PrintTicket.PageOrientation = PageOrientation.Landscape;
                
                if (prDlg.ShowDialog().Value)
                {
                    var rng = prDlg.PageRange;
                    if (rng.PageTo > 0)
                    {
                        int i = 1;
                        var documentRollUp = new RollUpDocument();
                        var ix = documentRollUp.AddDocument();
                        foreach (var page in sourcePages)
                        {
                            if (i >= rng.PageFrom && i <= rng.PageTo)
                                documentRollUp.AddPage(ix, page.PageContent.Source, (page.PageContent as IUriContext).BaseUri);
                            i++;
                        }
                        var seq = documentRollUp.FixedDocumentSequence;
                        prDlg.PrintDocument(seq.DocumentPaginator, Name);
                    }
                    else
                        prDlg.PrintDocument(ReportDoc.DocumentPaginator, Name);
                    if (RepFactory is IReportPrintHistory)
                        ((IReportPrintHistory)RepFactory).PutHistory();
                    if (PrintPressedEvent != null)
                    {
                        PrintPressedEvent(this, new EventArgs());
                    }
                }
            }
        }

        void LoadPrintPackage(List<object> pkg, string caption, ReportPaperSize reportPaperSize = ReportPaperSize.A4Portrait )
        {
            Name = caption;
            var docs = new List<FixedDocumentSequence>();

            foreach (var template in pkg)
            {
                if (template is IImagePrintFrame) ((IImagePrintFrame)template).InitImage();
                if (template is FixedDocumentSequence)
                {
                    docs.Add((FixedDocumentSequence)template);
                    continue;
                }

                var packUriName = string.Format("{0}//tmp{1}.xps", Path.GetTempPath(), DateTime.Now.Ticks); //string.Format("pack://tmp{0}.xps", DateTime.Now.Ticks);
                PackUriNames.Add(packUriName); // запомнили для дальнейшей подчистки

                docs.Add(
                    Cfg.CreateReport(template)
                        .WriteToPackage(packUriName, reportPaperSize));
            }
            Size pageSize = docs[0].DocumentPaginator.PageSize;
            ReportDoc = docs.Count == 1 ? docs[0] : DocMerger.SplitedDoc(docs);
            if (ReportDoc.DocumentPaginator.PageSize != pageSize)
            {
                ReportDoc.DocumentPaginator.PageSize = pageSize;
            }

        }

        public void PrintReport<TFactory, T>(T initValue, ReportPaperSize reportPaperSize/*bool isPortret*/) where TFactory : IReportfactoryBase<T>
        {
            Worker.Do(() =>
                          {
                              var factory = Cfg.Resolve<TFactory>();
                              factory.InitTemplateConstructor();
                              RepFactory = factory;
                              var objList = factory.InitPages(initValue);
                              return new {objList, name = factory.Name};
                          },
                      ret => LoadPrintPackage(ret.objList, ret.name, /*isPortret*/reportPaperSize));
        }

        public string SaveReport<TFactory, T>(T initValue, ReportPaperSize reportPaperSize/*bool isPortret*/) where TFactory : IReportfactoryBase<T>
        {
            var factory = Cfg.Resolve<TFactory>();
            factory.InitTemplateConstructor();
            RepFactory = factory;
            var objList = factory.InitPages(initValue);
            LoadPrintPackage(objList, factory.Name, /*isPortret*/reportPaperSize);
            var tempFileName = string.Format(@"{0}\{1}.xps", Path.GetTempPath(), "reportrsave");
            //проверим существует ли тот самый файл, если да то непорядок и мочим
            var fl = new FileInfo(tempFileName);
            if (fl.Exists) fl.Delete();
            var xpsDocument = new XpsDocument(tempFileName, FileAccess.ReadWrite);
            XpsDocumentWriter xpsDocumentWriter = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
            xpsDocumentWriter.Write(ReportDoc);
            xpsDocument.Close();
            return tempFileName;
        }


        #region IFrameForMultiWorkplace Members

        public string Name { get; set; }
        public bool CanClose
        {
            get
            {
                foreach (var pack in PackUriNames)
                    PackageStore.RemovePackage(new Uri(pack));
                GC.Collect();
                return true;
            }
        }

        #endregion

        // Declare the event.
        public event EventHandler PrintPressedEvent;

        public void PrintReportFromFile(string path)
        {
            ReportDoc = new XpsDocument(path,FileAccess.Read).GetFixedDocumentSequence();
        }
    }

    public interface IImagePrintFrame
    {
        void InitImage();
    }
}